﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using Utils;
using Utils.Extensions.WinForms;

namespace StockAccessors.Interdin.Engine
{
	[DebuggerDisplay("Connected = {Connected}")]
	internal class Accessor : PropertyChangedNotifier, IStockDataAccessor, IOrderExecutor
	{
		#region Attributes

		private readonly FuturesPageReader _futurePageReader;
		private readonly CfdPageReader _cfdPageReader;
		private readonly ConnectionManager _connectionManager;

		private readonly OrderExecutor _orderExecutor;
		private readonly AccessorEngine _engine;

		#endregion

		#region Properties

		public List<AccessorGroup> Groups
		{
			get
			{
				return new List<AccessorGroup> { this.Ibex35, this.MEFFFutures, this.EUREXFutures, this.OtherIndexFutures, this.EnergyAndMaterialsFutures, this.CurrencyFutures, this.EuroStoxx50, this.ContinuousMarket };
			}
		}

		private AccessorGroup Ibex35
		{
			get
			{
				return _cfdPageReader != null ? _cfdPageReader.Ibex35 : null;
			}
		}

		private AccessorGroup MEFFFutures
		{
			get
			{
				return _futurePageReader != null ? _futurePageReader.MEFFFutures : null;
			}
		}

		private AccessorGroup EUREXFutures
		{
			get
			{
				return _futurePageReader != null ? _futurePageReader.EUREXFutures : null;
			}
		}

		private AccessorGroup OtherIndexFutures
		{
			get
			{
				return _futurePageReader != null ? _futurePageReader.OtherIndexFutures : null;
			}
		}

		private AccessorGroup EnergyAndMaterialsFutures
		{
			get
			{
				return _futurePageReader != null ? _futurePageReader.EnergyAndMaterialsFutures : null;
			}
		}

		private AccessorGroup CurrencyFutures
		{
			get
			{
				return _futurePageReader != null ? _futurePageReader.CurrencyFutures : null;
			}
		}

		private AccessorGroup EuroStoxx50
		{
			get
			{
				return _cfdPageReader != null ? _cfdPageReader.EuroStoxx50 : null;
			}
		}

		private AccessorGroup ContinuousMarket
		{
			get
			{
				return _cfdPageReader != null ? _cfdPageReader.ContinuousMarket : null;
			}
		}

		public IStockDataAccessorInformation Information { get; private set; }

		public bool Connected
		{
			get
			{
				return _engine.Connected;
			}
		}

		public bool IsSimulationEnabled
		{
			get
			{
				return _orderExecutor.IsSimulationEnabled;
			}
			set
			{
				_orderExecutor.IsSimulationEnabled = value;
			}
		}

		#endregion

		#region Public Methods

		public Accessor(string user, string password)
		{
			_connectionManager = new ConnectionManager(user, password);
			_futurePageReader = new FuturesPageReader();
			_cfdPageReader = new CfdPageReader();
			
			_futurePageReader.ErrorDetected += this.ErrorDetected; // Local object
			_cfdPageReader.ErrorDetected += this.ErrorDetected; // Local object

			_orderExecutor = new OrderExecutor(_futurePageReader, _cfdPageReader);

			_engine = new AccessorEngine(_connectionManager, _cfdPageReader, _futurePageReader);
			_engine.PropertyChanged += this.Engine_PropertyChanged; // Local object
			_engine.Start();

			this.Information = new AccessorInformation(_engine, _futurePageReader, _cfdPageReader);
		}

		public void Connect()
		{
			_engine.AddOrder(AccessorMessageType.Connect);
		}

		public void ReadOnce()
		{
			_engine.AddOrder(AccessorMessageType.ReadOnce);
		}

		public OperationExecutionResult ExecuteMarketOrder(string symbol, int volume, bool buySell)
		{
			_orderExecutor.Cookies = _connectionManager.Cookies;
			return _orderExecutor.ExecuteMarketOrder(symbol, volume, buySell);
		}

		public OperationExecutionResult ExecuteMarketOrderInOpeningBid(string symbol, int volume, bool buySell)
		{
			throw new NotImplementedException();
		}

		public void ExecuteLimitedOrder(string symbol, int volume, bool buySell, decimal value)
		{
			_orderExecutor.Cookies = _connectionManager.Cookies;
			_orderExecutor.ExecuteLimitedOrder(symbol, volume, buySell, value);
		}

		public void Disconnect()
		{
			_engine.AddOrder(AccessorMessageType.Disconnect);
		}

		public void OpenBrowser()
		{
			BrowserWindow window = new BrowserWindow();

			if (this.Information.Connected)
			{
				window.SetCookies(_connectionManager.Cookies, "http://www.interdin.com");
				window.SetCookies(_connectionManager.Cookies, "http://www.interdinfuturos.com");
				window.Show();
				window.Navigate(new Uri("https://www.interdinfuturos.com/Broker/Futuros.asp?" + string.Format(@"nc={0}", _connectionManager.ContractNumber)));
			}
			else
			{
				window.Show();
				window.Navigate(new Uri("https://www.interdin.com/"));				
			}
		}

		#endregion

		#region Event Handlers

		private void ErrorDetected(object sender, EventArgs e)
		{
			_engine.AddOrder(AccessorMessageType.Reconnect);
		}

		private void Engine_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			base.OnPropertyChanged(e.PropertyName);
		}

		#endregion

		#region IDisposable

		protected bool Disposed { get; private set; }

		private void Dispose(bool disposing)
		{
			if (!this.Disposed)
			{
				this.InternalDispose(disposing);
			}

			this.Disposed = true;
		}

		protected virtual void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				if (_engine != null)
				{
					_engine.PropertyChanged -= Engine_PropertyChanged;
					_engine.Stop();
				}

				if (_orderExecutor != null)
				{
					_orderExecutor.Dispose();	
				}

				if (this.Information != null)
				{
					this.Information.Dispose();					
				}

				_futurePageReader.Dispose();
				_cfdPageReader.Dispose();

				if (_engine != null)
				{
					_engine.Dispose();
				}
			}

			// Dispose here only unmanaged objects 
			// Don’t use managed objects here because maybe 
			// they have been finalized already
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		~Accessor()
		{
			this.Dispose(false);
		}

		#endregion

	}
}
